package org.dxy.infrastructure.adapter.repository;

import cn.hutool.core.util.EnumUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dxy.domain.port.repository.IWorkOrderRepository;
import org.dxy.domain.event.workorder.*;
import org.dxy.domain.model.aggregate.WorkOrder;
import org.dxy.domain.model.aggregate.impl.WorkOrderAggRoot;
import org.dxy.domain.model.valobj.WorkOrderId;
import org.dxy.infrastructure.persistent.db.mybatispuls.po.DomainEventPo;
import org.dxy.infrastructure.persistent.db.mybatispuls.service.DomainEventService;
import org.springframework.stereotype.Repository;

import java.util.List;

@Slf4j
@Repository
@RequiredArgsConstructor
public class WorkOrderRepository implements IWorkOrderRepository {
    private final DomainEventService domainEventService;
    private final ObjectMapper objectMapper;


    @Override
    public WorkOrder findById(Long workOrderId) {
        List<DomainEventPo> domainEventPoList = domainEventService.getEventListByAggregateId(workOrderId);
        
        if (domainEventPoList == null || domainEventPoList.isEmpty()) {
            log.error("工单 {} 没有相关事件", workOrderId);
            return null;
        }
        
        return replayEvents(workOrderId, domainEventPoList);
    }

    @Override
    public WorkOrder findByCode(String workOrderCode) {
        return null;
    }

    @Override
    public boolean existsByCode(String workOrderCode) {
        try {
            // 查询所有工单创建事件
            List<DomainEventPo> createdEvents = domainEventService.getEventsByEventType(
                WorkOrderEventTypeEnum.CREATED.getKey()
            );
            
            for (DomainEventPo eventPo : createdEvents) {
                try {
                    WorkOrderCreatedEvent event = objectMapper.readValue(
                        eventPo.getEventData(), 
                        WorkOrderCreatedEvent.class
                    );
                    
                    if (workOrderCode.equals(event.workOrderCode())) {
                        return true;
                    }
                } catch (Exception e) {
                    log.error("解析工单创建事件失败", e);
                }
            }
            
            return false;
        } catch (Exception e) {
            log.error("检查工单编码存在性失败，workOrderCode: {}", workOrderCode, e);
            return false;
        }
    }

    @Override
    public int getMaxSequenceByDatePrefix(String datePrefix) {
        try {
            // 查询所有工单创建事件
            List<DomainEventPo> createdEvents = domainEventService.getEventsByEventType(
                WorkOrderEventTypeEnum.CREATED.getKey()
            );
            
            int maxSequence = 0;
            
            for (DomainEventPo eventPo : createdEvents) {
                try {
                    WorkOrderCreatedEvent event = objectMapper.readValue(
                        eventPo.getEventData(), 
                        WorkOrderCreatedEvent.class
                    );
                    
                    String workOrderCode = event.workOrderCode();
                    if (workOrderCode != null && workOrderCode.startsWith(datePrefix)) {
                        // 提取序号部分，格式：WO-20250916-001
                        String sequencePart = workOrderCode.substring(datePrefix.length());
                        try {
                            int sequence = Integer.parseInt(sequencePart);
                            maxSequence = Math.max(maxSequence, sequence);
                        } catch (NumberFormatException e) {
                            log.warn("工单编码格式异常: {}", workOrderCode);
                        }
                    }
                } catch (Exception e) {
                    log.error("解析工单创建事件失败", e);
                }
            }
            
            return maxSequence;
        } catch (Exception e) {
            log.error("获取最大序号失败，datePrefix: {}", datePrefix, e);
            return 0;
        }
    }

    @Override
    public void deleteById(Long aLong) {

    }

    @Override
    public boolean save(WorkOrder workOrder) {
        return true;
    }

    /**
     * 通过事件重放重建工单聚合根
     * @param workOrderId 工单ID
     * @param eventEntities 事件实体列表
     * @return 重建的工单聚合根
     */
    private WorkOrder replayEvents(Long workOrderId, List<DomainEventPo> eventEntities) {
        WorkOrderAggRoot.WorkOrderAggRootBuilder builder = WorkOrderAggRoot.builder()
                .workOrderId(WorkOrderId.of(workOrderId));
        
        try {
            WorkOrderAggRoot workOrder = builder.build();
            
            for (DomainEventPo eventEntity : eventEntities) {
                applyEvent(workOrder, eventEntity);
            }
            
            // 清理重放过程中可能产生的事件
            workOrder.clearDomainEvents();

            log.debug("成功回放工单 {} 的 {} 条事件", workOrderId, eventEntities.size());
            return workOrder;
            
        } catch (Exception e) {
            log.error("Failed to replay events for workOrderId: {}", workOrderId, e);
            throw new RuntimeException("事件重放失败: " + e.getMessage(), e);
        }
    }

    /**
     * 应用单个事件到聚合根
     * @param workOrder 工单聚合根
     * @param eventEntity 事件实体
     */
    private void applyEvent(WorkOrderAggRoot workOrder, DomainEventPo eventEntity) {
        try {
            String eventType = eventEntity.getEventType();
            String eventData = eventEntity.getEventData();

            if (eventType == null) {
                log.error("工单ID {} 的事件类型为空，无法处理事件。", eventEntity.getAggregateId());
                return;
            }

            WorkOrderEventTypeEnum eventTypeEnum = EnumUtil.getBy(
                    WorkOrderEventTypeEnum.class,
                    p -> eventType.equals(p.getKey())
            );

            if (eventTypeEnum == null) {
                log.error("工单ID {} 的事件类型未知：{}，无法处理事件。", eventEntity.getAggregateId(), eventType);
                return;
            }

            switch (eventTypeEnum) {
                case CREATED -> {
                    WorkOrderCreatedEvent event = objectMapper.readValue(eventData, WorkOrderCreatedEvent.class);
                    workOrder.applyCreatedEvent(event);
                }
                case UPDATED -> {
                    WorkOrderUpdatedEvent event = objectMapper.readValue(eventData, WorkOrderUpdatedEvent.class);
                    workOrder.applyUpdatedEvent(event);
                }
                case RELEASED -> {
                    WorkOrderReleasedEvent event = objectMapper.readValue(eventData, WorkOrderReleasedEvent.class);
                    workOrder.applyReleasedEvent(event);
                }
                case STARTED -> {
                    WorkOrderStartedEvent event = objectMapper.readValue(eventData, WorkOrderStartedEvent.class);
                    workOrder.applyStartedEvent(event);
                }
                case SUSPENDED -> {
                    WorkOrderSuspendedEvent event = objectMapper.readValue(eventData, WorkOrderSuspendedEvent.class);
                    workOrder.applySuspendedEvent(event);
                }
                case RESUMED -> {
                    WorkOrderResumedEvent event = objectMapper.readValue(eventData, WorkOrderResumedEvent.class);
                    workOrder.applyResumedEvent(event);
                }
                case COMPLETED -> {
                    WorkOrderCompletedEvent event = objectMapper.readValue(eventData, WorkOrderCompletedEvent.class);
                    workOrder.applyCompletedEvent(event);
                }
                case CLOSED -> {
                    WorkOrderClosedEvent event = objectMapper.readValue(eventData, WorkOrderClosedEvent.class);
                    workOrder.applyClosedEvent(event);
                }
                case CANCELLED -> {
                    WorkOrderCancelledEvent event = objectMapper.readValue(eventData, WorkOrderCancelledEvent.class);
                    workOrder.applyCancelledEvent(event);
                }
                case DELETED -> {
                    WorkOrderDeletedEvent event = objectMapper.readValue(eventData, WorkOrderDeletedEvent.class);
                    workOrder.applyDeletedEvent(event);
                }
                default -> {
                    log.warn("工单ID {} 的事件类型 {} 未处理。", eventEntity.getAggregateId(), eventTypeEnum);
                }
            }
            
        } catch (Exception e) {
            log.error("应用工单ID {} 的事件类型 {} 失败，异常信息：", eventEntity.getAggregateId(), eventEntity.getEventType(), e);
            throw new RuntimeException("应用事件失败: " + e.getMessage(), e);
        }
    }
}
